﻿using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;


namespace YOLO4DMF {
    public partial class Form1 : Form {
        string model_path = string.Empty;
        string video_path = string.Empty;
        float model_confidence;
        float model_nms_threshold;
        string cameraID = "off";
        uint[] anchors = new uint[8];
        uint selectedAnchorNum = 0;
        bool state = false;
        bool background_worker_start = false;
        enum TASK { NONE, CALIBRATE, DETECT, INIT_TRACK, TRACK };
        TASK task = TASK.NONE;

        public Form1() {
            InitializeComponent();
            init();
        }

        private void btn_start_Click(object sender, EventArgs e) {
            if (cameraID != "off") {
                Console.WriteLine("Open camera ...");
                int ID = int.Parse(cameraID);
                state = openCamera(ID, 800, 600, 20);
                if (!state) throw new Exception("ERROR:\nCamera is not opened!");
                background_worker_start = true;
                sleep_ms = 1;
                if (background_worker == null) init();
            }
            else if (tbox_video.Text != "") {
                Console.WriteLine("Play video: {0}", video_path);
                state = openVideo(video_path);
                if (!state) throw new Exception("ERROR:\nVideo is not opened!");
                background_worker_start = true;
                sleep_ms = 100;
                if (background_worker == null) init();
            }
            else {
                MessageBox.Show("请先选择打开【摄像头】或【视频】", "Warning");
            }
        }

        private void btn_calibrate_Click(object sender, EventArgs e) {
            if (!background_worker_start) {
                MessageBox.Show("请先点击\"start!\"", "Warning");
                return;
            }
            if (data.CalibrationData.Default.isValid == true) {
                MessageBox.Show("已自动读入上次保存的锚点数据", "导入配置");
                anchors[0] = data.CalibrationData.Default.x1;
                anchors[1] = data.CalibrationData.Default.y1;
                anchors[2] = data.CalibrationData.Default.x2;
                anchors[3] = data.CalibrationData.Default.y2;
                anchors[4] = data.CalibrationData.Default.x3;
                anchors[5] = data.CalibrationData.Default.y3;
                anchors[6] = data.CalibrationData.Default.x4;
                anchors[7] = data.CalibrationData.Default.y4;
                selectedAnchorNum = 4;
            }
            else {
                selectedAnchorNum = 0;
            }
            task = TASK.CALIBRATE;
            gbox_cali.Visible = true;
            picturebox.Cursor = Cursors.Cross;
            transIsValid = false;
            calibrate_finished = false;
            this.WindowState = FormWindowState.Maximized;
        }

        private void btn_detect_Click(object sender, EventArgs e) {
            if (!background_worker_start) {
                MessageBox.Show("请先点击\"start!\"", "Warning");
                return;
            }
            Console.WriteLine("detect");
            background_worker_start = true;
            task = TASK.DETECT;
        }

        private void btn_track_Click(object sender, EventArgs e) {
            if (!background_worker_start) {
                MessageBox.Show("请先点击\"start!\"", "Warning");
                return;
            }
            task = TASK.INIT_TRACK;            
        }

        private void btn_stop_Click(object sender, EventArgs e) {
            background_worker_start = false;
            task = TASK.NONE;
            picturebox.Image = null;
            Thread.Sleep(100);
            close();
        }

        private void Form1_Load(object sender, EventArgs e) { }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            MessageBoxButtons mess = MessageBoxButtons.OKCancel;
            DialogResult dr = MessageBox.Show("是否确认退出？", "退出", mess);
            if (dr != DialogResult.OK) {
                e.Cancel = true;
            }
            else {
                this.Dispose();
                this.Close();
                System.Environment.Exit(0);
            }
        }

        private void picturebox_MouseDown(object sender, MouseEventArgs e) {
            if (task != TASK.CALIBRATE) return;
            if (selectedAnchorNum < 4) {
                if (picturebox.Image.Width > picturebox.Width || picturebox.Image.Height > picturebox.Height) {
                    Console.WriteLine("picturebox.Width = {0}, picturebox.Height = {1})", picturebox.Width, picturebox.Height);
                    Console.WriteLine("Image.Width = {0}, Image.Height = {1})", picturebox.Image.Width, picturebox.Image.Height);
                    Console.WriteLine("点击坐标 x = {0}, y = {1}\n", e.X, e.Y);
                    //    throw new Exception("ERROR:\nImage is too big for picturebox!");
                }
                int dx = (picturebox.Width - picturebox.Image.Width) / 2;
                int dy = (picturebox.Height - picturebox.Image.Height) / 2;
                int x = e.X - dx;
                int y = e.Y - dy;
                anchors[2 * selectedAnchorNum] = (uint)x;
                anchors[2 * selectedAnchorNum + 1] = (uint)y;
                Console.WriteLine("Anchor[{0}]: ({1}, {2})", selectedAnchorNum, x, y);
                selectedAnchorNum++;
            }
            else {
                MessageBox.Show("最多只能选择4个锚点", "Warning");
            }
        }

        private void btn_cali_confirm_Click(object sender, EventArgs e) {
            calibrate_finished = true;
        }

        private void btn_cali_backspace_Click(object sender, EventArgs e) {
            if (selectedAnchorNum > 0) selectedAnchorNum--;
        }

        private void btn_cali_exit_Click(object sender, EventArgs e) {
            gbox_cali.Visible = false;
            picturebox.Cursor = Cursors.Default;
            task = TASK.NONE;
        }

        private void btn_load_model_Click(object sender, EventArgs e) {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "模型文件 | *.torchscript;";
            dialog.Title = "打开模型";
            if (dialog.ShowDialog() == DialogResult.OK) {
                Console.Write("Model loading...", "");
                model_path = dialog.FileName;
                tbox_model.Text = model_path;
                state = loadYOLOModel(model_path);
                if (!state) throw new Exception("ERROR:\nModel loading failed!");
                Console.WriteLine("Done.");
            }
        }

        private void btn_load_video_Click(object sender, EventArgs e) {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "视频文件 | *.mp4;";
            dialog.Title = "打开视频";
            if (dialog.ShowDialog() == DialogResult.OK) {
                Console.Write("Video loading...", "");
                video_path = dialog.FileName;
                tbox_video.Text = video_path;
                Console.WriteLine("Done.");
            }
        }

        private void cbox_camera_SelectedIndexChanged(object sender, EventArgs e) {
            cameraID = cbox_camera.SelectedItem.ToString();
        }

        private void textBox1_TextChanged(object sender, EventArgs e) { }

        private void label4_Click(object sender, EventArgs e) { }

        private void numUpDown_conf_ValueChanged(object sender, EventArgs e) {
            model_confidence = float.Parse(numUpDown_conf.Value.ToString());
            setYOLOConfidence(model_confidence);
        }

        private void numUpDown_nms_threshold_ValueChanged(object sender, EventArgs e) {
            model_nms_threshold = float.Parse(numUpDown_nms_threshold.Value.ToString());
            setYOLONMSThreshold(model_nms_threshold);
        }
    }
}